﻿using System;
using System.Collections.Generic;
using System.Text;

namespace simulatMeter.Lib
{

    /// <summary>
    /// 数据帧方向 枚举类
    /// </summary>
    public enum DIRECTION { Master, Slater }
    
    /// <summary>
    /// 控制码类型 枚举类
    /// </summary>
    public enum CodeStyle
    {
        Read = 0x11,
        ReadMore = 0x12,
        Write = 0x14,
        ReadAddress = 0x13,
        WriteAddress = 0x15,

        //97 
        Read97 = 0x01,
    }

    /// <summary>
    /// 控制码 基类
    /// </summary>
    public class Code
    {
        public byte code;

        public Code(byte c) { code = c; }
        public DIRECTION dir
        {
            get { if ((byte)(code & 0x80) == 0x80)return DIRECTION.Master; else return DIRECTION.Slater; }
            set
            {
                if (value == DIRECTION.Master) code &= 0x80;
                else code &= 0x7f;
            }
        }
        public CodeStyle c
        {
            get
            {
                return (CodeStyle)(code & 0x7F);
            }
            set {
                code &= 0x80;
                code |= (byte)(value);
            }
        }
        public byte Value { get { return code; } set { code = Value; } }
    }
   
    /// <summary>
    /// 645 数据包基类
    /// </summary>
    public   class MeterPacket
    {
        #region 私有数据
        /// <summary>
        /// 数据帧缓冲
        /// </summary>
        static int MeterPacketMax = 2048;
        private byte[] _data = new byte[MeterPacketMax];
        #endregion



        #region  公有数据，数据帧属性
        /// <summary>
        /// 起始字节
        /// </summary>
        public byte startByte { get { return _data[0]; } set { _data[0] = value; } }
        
        /// <summary>
        /// 电表表号，从低位到高位
        /// </summary>
        public byte[] meterNumber
        {
            get { byte[] n = new byte[6]; Array.Copy(_data, 1, n, 0, 6); return n; }
            set { if (value == null)return; Array.Copy(value, 0, _data, 1, 6); }
        }

       /// <summary>
       /// 电表表号，从高到低位
       /// </summary>
        public byte[] meterNumberView
        {
            get
            {
                byte[] n = meterNumber;
                Ulitily.ShareClass.ReversedBytes(n, 6);
                return n;
            }
        }

       /// <summary>
       /// 电表表号 0x0123456789012
       /// </summary>
        public UInt64 meterNumberHex
        {
            get
            {
                byte[] d = meterNumber;
                Ulitily.ShareClass.ReversedBytes(d, 6);
                return UInt64.Parse(Ulitily.ShareClass.hexByteArrayToString(d).Replace("-", ""),
                    System.Globalization.NumberStyles.HexNumber);
            }
            set
            {
                _data[1] = (byte)((value >> 0) & 0xff);
                _data[2] = (byte)((value >> 8) & 0xff);
                _data[3] = (byte)((value >> 16) & 0xff);
                _data[4] = (byte)((value >> 24) & 0xff);
                _data[5] = (byte)((value >> 32) & 0xff);
                _data[6] = (byte)((value >> 40) & 0xff);
            }
        }
        

        /// <summary>
        /// 重启字节
        /// </summary>
        public byte restartByte { get { return _data[7]; } set { _data[7] = value; } }
        
        /// <summary>
        /// 控制码
        /// </summary>
        public Code code { get { return new Code(_data[8]); } set { _data[8] = value.code; } }
        
        /// <summary>
        /// 用户数据长度
        /// </summary>
        public int len { get { return (int)(_data[9]); } set { _data[9] = (byte)value; } }
        
        /// <summary>
        ///用户数据 ，带33H
        /// </summary>
        public byte[] data
        {
            get
            {
                if (len == 0) return null;
                byte[] nb = new byte[len];
                Array.Copy(_data, 10, nb, 0, nb.Length);
                return nb;
            }
            set
            {
                if (value == null) { len = 0; return; }
                len = value.Length;
                Array.Copy(value, 0, _data, 10, len);

            }
        }

       /// <summary>
       /// 用户数据，不带33H
       /// </summary>
        public byte[] dataRaw
        {
            get
            {
                if (len == 0) return null;
                byte[] nb = new byte[len];
                for (int i = 0; i < nb.Length; i++)
                {
                    nb[i] = (byte)(_data[10 + i] - 0x33);
                }
                return nb;
            }
            set
            {
                if (value == null) { len = 0; return; }
                len = value.Length;
                Array.Copy(value, 0, _data, 10, len);
                for (int i = 0; i < len; i++)
                {
                    _data[10 + i] += 0x33;
                }

            }
        }

       /// <summary>
       /// DI 97 数据标识
       /// </summary>
        public UInt16 DI97
        {
            get
            {
                UInt16 v = 0;
                Ulitily.ShareClass.BytesToUInt16(_data, 10, ref v,0x33);
                return v;
            }

            set
            {
                Ulitily.ShareClass.Uint16ToBytes(value, _data, 10,0x33);
            }
        }


       /// <summary>
       /// DI 07 数据标识
       /// </summary>
        public UInt32 DI07
        {
            get
            {
                UInt32 v = 0;
                Ulitily.ShareClass.BytesToUInt32(ref v, _data, 10,0x33);
                return v;
            }

            set
            {
                Ulitily.ShareClass.UInt32ToBytes(value, _data, 10,0x33);
            }
        }


        /// <summary>
        /// 读取 数据包中，di对应的数据
        /// </summary>
        /// <param name="offset"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public byte[] DIData(int offset,int len)
        {
            byte[] v = new byte[len];
            Array.Copy(dataRaw, offset, v, 0, len);
            Ulitily.ShareClass.ReversedBytes(v, len);
            return v;
        }

        /// <summary>
        /// cs 码
        /// </summary>
        public byte cs { get { return _data[10+len]; } set { _data[10+len] = value; } }
        
        /// <summary>
        /// 结束字节
        /// </summary>
        public byte endByte { get { return _data[11 + len]; } set { _data[11 + len] = value; } }



        #endregion



        #region 构造
        public MeterPacket(Code c){code = c;}
        public MeterPacket(Code c, byte[] da) { code = c; data = da; }
        public MeterPacket(byte[] meter, Code c, byte[] da) { meterNumber = meter; code = c; data = da; }

        /// <summary>
        /// packetdata[offet] 的数据 已经 是 一个数据包了 
        /// </summary>
        /// <param name="packetdata"></param>
        /// <param name="offset"></param>
        /// <param name="len"></param>
        public MeterPacket(byte[] packetdata, int offset, int len)
        {
            if (packetdata == null) return;
            if (packetdata.Length <= offset) return;
            if (packetdata.Length < offset + len) { len = packetdata.Length - offset; }
            Array.Copy(packetdata, 0, _data, 0, len);
        }
        #endregion







        /// <summary>
        /// 生成一个数据帧
        /// </summary>
        /// <returns></returns>
        public byte[] toBytes()
        {
            startByte = restartByte = 0x68;
            cs = Ulitily.ShareClass.CheckSum8(_data, 0, 10 + len);
            endByte = 0x16;

            byte[] copydata = new byte[len + 12];
            Array.Copy(_data, 0, copydata, 0, copydata.Length);
            return copydata;
        }


        #region 接收状态机，解析一个数据包

        static int state=0,ll=0,offset =0,clen=0; 
        static byte[] pack = new byte[MeterPacket.MeterPacketMax];
        public static MeterPacket toPackcet(byte c)
        {

             


            switch(state){

                    //开始
                case 0:
                    if(c!=0x68){goto error;}

                    pack [offset] = c;
                    offset++;
                    state = 1;
                    return null;
                case 1:
                    pack[offset]=c;
                    offset++;
                    if(offset==7)state = 2;
                    return null;

                case 2:
                    if(c!=0x68)goto error;
                    else {
                        pack[offset] = 0x68;
                        offset++;
                        state = 3;
                        return null;
                    }

                    //code
                case 3:
                    pack[offset] = c;
                    offset++;
                    state =4;
                    return null;
                case 4:
                    pack[offset] = c;
                    offset++;
                    ll = clen = (int)c;
                    state = 5;
                    return null;

                case 5:
                    //接收数据
                    if(clen >0){
                        pack[offset] =c;
                        offset++;
                        clen--;
                        return null;

                    }else{

                        //接收到cs code
                        byte cs = Ulitily.ShareClass.CheckSum8(pack,0,10+ll);
                        if(cs == c){
                            pack[offset]= c;
                            offset++;
                            state = 6;
                        }else{

                            goto error;
                        }
                    }

                    return null;

                // 0x16
                case 6:
                    if(c == 0x16){
                        pack[offset] = c;
                        offset++;

                        //接收到一个正确的数据包
                        MeterPacket p = new MeterPacket(pack,0,offset);

                        Array.Clear(pack,0,pack.Length);
                        state = 0;
                        ll = clen = 0;
                        offset = 0;


                        return p;

                    }

                    else goto error;



            }


            error:
            Array.Clear(pack,0,pack.Length);
            state = 0;
            offset = 0;
            clen= 0;
            ll= 0;
            return null;
        }

        #endregion


    
    }
}
